# generate grammar rules from parsed sentences
from rai.logger.logger import *
import rai.sem.parse_util as parse_util

# format string for the grammar rules
TV_FORMAT_STRING = "TV[num='sg',SEM=<\\X y.X(\\x.%s(y,x))>,tns='pres'] -> '%s'"
IV_FORMAT_STRING = "IV[num='sg', SEM=<\\x.%s(x)>, tns='pres'] -> '%s'"
PROPN_FORMAT_STRING = "PropN[-loc, num='sg', SEM=<\P.P(%s)>] -> '%s'"
N_FORMAT_STRING = "N[num='sg', SEM=<%s>] -> '%s'"


def isAllowedPredicate(vn_sem_arg):
    """
        Returns true if the vn_sem_arg is allowed as a predicate in the final semantic-expression

        @param vn_sem_argparam: type is VNSemanticArgWrapper 
    """
    #sub_expr = "%s(e, %s)" % (arg.name, free_var)
    if vn_sem_arg.type == "Event":
        return False
    elif vn_sem_arg.type == "ThemRole" and vn_sem_arg.name == "Theme":
        return True
    elif vn_sem_arg.type == "ThemRole" and vn_sem_arg.name == "Agent":
        return True
    elif vn_sem_arg.type == "ThemRole" and vn_sem_arg.name == "Experiencer":
        return True
    elif vn_sem_arg.type == "ThemRole" and vn_sem_arg.name == "Stimulus":
        return True
    else:
        return False

def convertVNSemWrapperToGrammarString(vn_sem_wrapper, verb_inf):
    """
        Converts the vn_sem_wrapper to a string representation of the grammar rule
        @param vn_sem_wrapper: a VNSemanticWrapper class
        
        TV[num=sg,SEM=<\X y.X(\e x.(chase(e) & agent(e,y) & patient(e,x)))>,tns=pres] -> 'chases'
        TV[num=pl,SEM=<\X y.X(\e x.(chase(e) & agent(e,y) & patient(e,x)))>,tns=pres] -> 'chase'

    """
    verb = vn_sem_wrapper.name
    
    themRoles = [] # all the predicates
    for arg in vn_sem_wrapper.args:
        #print arg.type, arg.name
        if isAllowedPredicate(arg):
            # the arg is allowed as predicate, add it to the themerole list
            themRoles.append(arg)
        else:
            pass
    
    start_ord = ord('z') - len(themRoles) + 1
    free_var_ord = ord('z') - len(themRoles) + 1
    #print ord('z') - len(themRoles) + 1
    #print chr(ord('z') - len(themRoles) + 1)
    
    # first comes the verb
    line = "%s(e)" % (verb_inf,)
    for arg in themRoles:
        line = line + " & %s(e, %s)" % (arg.name.lower(), chr(free_var_ord))
        free_var_ord = free_var_ord + 1
    #print line

    last_var_ord = free_var_ord - 1
    line = "\e "+chr(last_var_ord)+".(" + line + ")"
    #print line
    #print free_var_ord - 1, start_ord
    for i in range(last_var_ord - 1, start_ord, -1):
        #print i, chr(i)
        line = "\\"+chr(i)+ "."+str(chr(i-1)).upper()+"(" + line + ")"
    #print line
    if len(themRoles) == 1:
        rules = []
        verb_sg = verb_inf + "s"
        verb_pl = verb_inf
        rule0 = "IV[num=sg,SEM=<%s>,tns=pres] -> '%s'" % (line, verb_sg)
        rule1 = "IV[num=pl,SEM=<%s>,tns=pres] -> '%s'" % (line, verb_pl)
        rules.append(rule0)
        rules.append(rule1)
        return rules
    elif len(themRoles) == 2:
        # two predicates
        line = "\\Z e y.Z(e, (%s))" % (line,)
        rules = []
        verb_sg = verb_inf + "s"
        verb_pl = verb_inf
        rule0 = "TV[num=sg,SEM=<%s>,tns=pres] -> '%s'" % (line, verb_sg)
        rule1 = "TV[num=pl,SEM=<%s>,tns=pres] -> '%s'" % (line, verb_pl)
        rules.append(rule0)
        rules.append(rule1)
        return rules
        
        pass
    print chr(start_ord)+"."
    line = "(" + line + ")"
    rule_sem = "\X y.X(\e x.(chase(e) & agent(e,y) & patient(e,x)))"
    

def addTVToGrammar(verb, world):
    """
        add a Transitive verb to the grammar.lexicon
        e.g.: TV[num=sg,SEM=<\\X y. X(\\x. chase(y,x))>,tns=pres] -> 'chases'
        TODO: handle difference between plural and singular
        TODO: handle different tenses (past, present)
        
        returns true when a new grammar rule was added, false if it already existed
        @return: (isNew, newRule<string>)
    """
    # check if the words exists in the grammar.productions()
    if  world.getGrammar().productions(rhs=verb) == []:
        # Transitive verb is not covered in lexicon of the grammar
        debug("verb '"+verb+"' is not covered in lexicon of the grammar, add it")
        f_sem = verb
        rh_value = verb
        line = TV_FORMAT_STRING % (f_sem, rh_value)
        #line = "TV[num='sg',SEM=<\\X y.X(\\x."+f_sem+"(y,x))>,tns='pres'] -> '"+rh_value+"'"
        world.addNewProduction(line)
        return (True, line)
    return (False, None)
    


def addIVToGrammar(verb, world):
    """
        add a Intransitive verb to the grammar.lexicon
        e.g.: IV[num=sg,SEM=<\\x. bark(x)>,tns=pres] -> 'barks'
    """
    # check if the words exists in the grammar.productions()
    if  world.getGrammar().productions(rhs=verb) == []:
        # Transitive verb is not covered in lexicon of the grammar
        debug("verb '"+verb+"' is not covered in lexicon of the grammar, add it")
        f_sem = verb
        rh_value = verb
        line = IV_FORMAT_STRING % (f_sem, rh_value)
        #line = "IV[num='sg', SEM=<\\x."+f_sem+"(x)>, tns='pres'] -> '"+rh_value+"'"
        world.addNewProduction(line)
        return (True, line)
    return (False, None)            

def addPopertyToGrammar(property, world, tags=None):
    """ add the property to the grammar.lexicon
        e.g. "N[num=sg,SEM=<singer>] -> 'singer' "
    """
    #TODO: make distiction between Noun and ProperNoun
    #print property
    # check if the words exists in the grammar.productions()
    if  world.getGrammar().productions(rhs=property) == []:
        # word is not covered in lexicon of the grammar
        debug("word '"+property+"' is not covered in lexicon of the grammar")
        f_sem = property
        rh_value = property
        # Noun can be further specified in ProperNoun
        # Lookup the word in the person database
        strippedNoun = parse_util.stripNoun(tags)
        line = None
        if len(strippedNoun) == 1:
            # only one word
            b_tag = strippedNoun[0][1] # brown tag
            if b_tag == "NP":
                line = PROPN_FORMAT_STRING % (f_sem, rh_value)
        else:
            line = N_FORMAT_STRING % (f_sem, rh_value)
        #line = "N[num='sg', sem=<"+f_sem+">] -> '"+rh_value+"'"
        world.addNewProduction(line)
        return (True, line)
    return (False, None)   